package com.example.xiaoshuo_yudu.controller;


import com.example.xiaoshuo_yudu.entity.Result;
import com.example.xiaoshuo_yudu.entity.ResultCode;
import com.example.xiaoshuo_yudu.entity.dto.LoginDTO;
import com.example.xiaoshuo_yudu.entity.entity.Users;
import com.example.xiaoshuo_yudu.entity.vo.EmailRegisterVo;
import com.example.xiaoshuo_yudu.entity.vo.LoginVO;
import com.example.xiaoshuo_yudu.service.UsersService;
import com.example.xiaoshuo_yudu.utils.JWTUtil;
import com.example.xiaoshuo_yudu.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;


import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 用户基本信息表 前端控制器
 * </p>
 *
 * @author xusen
 * @since 2025-07-25
 */
@RestController
@RequestMapping("/api/auth")
public class UsersController {
    @Autowired
    private UsersService usersService;
    @Value("${xiaoshuo.jwt.key}")
    private String key;
    //令牌的过期时间，以小时为单位
    @Value("${xiaoshuo.jwt.access-token.expire-time:7200000}") // 默认2小时（毫秒）
    private long accessTokenExpireTime;

    @Value("${xiaoshuo.jwt.refresh-token.expire-time:604800000}") // 默认7天（毫秒）
    private long refreshTokenExpireTime;
    @Autowired
    private JwtUtils jwtUtils;
    /**
     * 处理发送验证码请求的控制器方法
     * 该方法响应GET请求，并根据用户提供的邮箱和类型发送相应的验证码
     *
     * @param email   用户输入的电子邮箱地址，使用@Email注解进行格式验证
     * @param type    请求类型，可以是"register"（注册）或"reset"（重置密码），使用@Pattern注解进行验证
     * @param request HttpServletRequest对象，用于获取请求的远程地址
     * @return 返回一个RestBean对象，包含执行结果，此处泛型为Void，表示不返回具体数据
     */
    @GetMapping("/ask-code")
    public Result<Void> askCode(@RequestParam @Email String email,
                                @RequestParam @Pattern(regexp = "(register|reset|modify)") String type,
                                HttpServletRequest request) {
        // 调用服务层方法生成验证码并发送到指定邮箱
        String massage = usersService.registerEmailVerifyCode(type, email, request.getRemoteAddr());
        // 根据返回的消息判断验证码发送是否成功
        if(massage == null)
            // 如果没有错误消息，表示发送成功，返回成功信息
            return Result.success();
        else
            // 如果有错误消息，表示发送失败，返回错误信息和状态码400
            return Result.failure(400,massage);
    }

    /**
     * 处理用户使用电子邮件注册的请求
     * 此方法通过POST请求接收用户信息，并调用账户服务进行注册
     *
     * @param registerVo 包含用户注册信息的EmailRegisterVo对象，包括电子邮件、密码等
     *                   该对象通过@Validated注解进行参数校验，确保数据完整性
     * @return 返回一个RestBean<Void>对象，表示注册操作的结果
     * RestBean封装了操作状态和可能的错误信息，便于前端处理
     */
    @PostMapping("/register")
    public Result<Void> register(@RequestBody @Validated EmailRegisterVo registerVo) {
        // 调用服务层方法进行注册操作，传入注册信息
        String massage = usersService.registerEmailAccount(registerVo);
        // 根据返回的消息判断注册是否成功
        if(massage == null)
            // 如果没有错误消息，表示注册成功，返回成功信息
            return Result.success();
        else
            // 如果有错误消息，表示注册失败，返回错误信息和状态码400
            return Result.failure(400,massage);
    }

    @PostMapping("/login")
    @Operation(summary = "通用登录")
    public Result<LoginVO> login(@RequestBody  @Valid LoginDTO loginDTO) {
        long expireTime = loginDTO.isRemember() ? refreshTokenExpireTime : accessTokenExpireTime;
        // 调用service登录
        Users users=usersService.login(loginDTO);
        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("userid", users.getUserId());
        claims.put("role", users.getRole()); // 直接存原始类型（如Integer），无需toString
        claims.put("username", users.getUsername()); // 补充username，供刷新令牌使用
        claims.put("remember", loginDTO.isRemember());
        System.out.println(claims);
        String token = JWTUtil.createJWT(
                key,// 签名
                expireTime,// 过期时间
                claims);
        LoginVO Loginvo = LoginVO.builder()
                .token(token)
                .userId(users.getUserId())
                .role(users.getRole())
                .username(users.getUsername())
                .expireTime(expireTime)
                .build();
        return Result.success(Loginvo);
    }
    @PostMapping("/logout")
    @Operation(summary = "退出登录")
    public Result logout(HttpServletRequest request) {
        // 获取token
        String authorization = request.getHeader("Authorization");
        if(jwtUtils.invalidateJwt(authorization)) {
            // 如果令牌成功列入黑名单，则返回成功信息
            return Result.success("退出登录成功");
        }
        return Result.failure(ResultCode.BUSINESS_ERROR,"退出登录失败");
    }

    @PostMapping("/token/refresh")
    public Result<LoginVO> refreshToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            return Result.failure(ResultCode.UNAUTHORIZED, "无效的令牌格式");
        }
        String oldToken = authHeader.substring(7);
        try {
            // 使用工具类解析令牌
            Map<String, Object> claims = JWTUtil.parseJWT(key, oldToken);
            if (claims == null) {
                return Result.failure(ResultCode.UNAUTHORIZED, "无效的令牌");
            }
            // 检查令牌是否在黑名单中
            String jti = claims.get("jti").toString();
            if (jwtUtils.isTokenBlacklisted(jti)) {
                return Result.failure(ResultCode.UNAUTHORIZED, "令牌已被注销");
            }
            // 生成新令牌前，先将旧令牌加入黑名单
            jwtUtils.invalidateJwt(authHeader);
            // 构建新令牌载荷
            Map<String, Object> newClaims = new HashMap<>();
            newClaims.put("userid", claims.get("userid"));
            newClaims.put("role", claims.get("role"));
            newClaims.put("username", claims.get("username"));
            newClaims.put("remember", claims.get("remember"));
            // 计算新令牌过期时间
            boolean remember = (Boolean) claims.get("remember"); // 已在登录时确保为Boolean
            long newExpireTime = remember ? refreshTokenExpireTime : accessTokenExpireTime;
            // 使用JWTUtil生成新令牌
            String newToken = JWTUtil.createJWT(key, newExpireTime, newClaims);
            // 构建返回结果
            LoginVO loginVO = LoginVO.builder()
                    .token(newToken)
                    .userId(Integer.valueOf(claims.get("userid").toString()))
                    .username(claims.get("username").toString())
                    .role(Integer.valueOf(claims.get("role").toString()))
                    .expireTime(remember? refreshTokenExpireTime : accessTokenExpireTime) // 补充
                    .build();
            return Result.success(loginVO);

        } catch (ExpiredJwtException e) {
            return Result.failure(ResultCode.UNAUTHORIZED, "令牌已过期，请重新登录");
        } catch (Exception e) {
            return Result.failure(ResultCode.UNAUTHORIZED, "无效的令牌");
        }
    }
}
